﻿using System;
using System.Drawing;
using System.Drawing.Text;
using System.Text;
using System.Windows.Forms;

namespace DotMatrixGenerator {
	public partial class frmMain : Form {
		Bitmap[] bitmaps;
		PictureBox[] pictureboxes;
		bool[,,] matrix_data;
		int grid_width = 16, grid_height = 16, grid_size = 10;
		int font_size = 16;
		int adjust_x = -3, adjust_y = 0;
		string font_name = "宋体";
		bool bold = false, italic = false;
		Font font;
		FontStyle font_style = FontStyle.Regular;

		public frmMain()
		{
			InitializeComponent();

			load_font_options();

			generate_matrix();
		}

		private void load_font_options()
		{
			InstalledFontCollection fonts = new InstalledFontCollection();
			FontFamily[] families = fonts.Families;

			foreach (FontFamily family in families) {
				comboFonts.Items.Add(family.Name);
			}

			try {
				comboFonts.SelectedItem = font_name;
			} catch (Exception) {

			}

			for (int count = 6; count < 25; count++) {
				comboFontSize.Items.Add(count);
			}

			comboFontSize.SelectedItem = font_size;

			for (int count = 6; count < 33; count++) {
				comboBoxGridWidth.Items.Add(count);
				comboBoxGridHeight.Items.Add(count);
			}

			comboBoxGridWidth.SelectedItem = grid_width;
			comboBoxGridHeight.SelectedItem = grid_height;
		}

		private void clean_matrix()
		{
			flowLayoutMatrix.Controls.Clear();
		}

		private void generate_matrix()
		{
			string words = txtWords.Text;
			if (words.Length == 0) { return; }

			clean_matrix();

			int words_length = words.Length;

			grid_width = (int)comboBoxGridWidth.SelectedItem;
			grid_height = (int)comboBoxGridHeight.SelectedItem;
			grid_size = trackBarGridSize.Value;
			font_name = comboFonts.SelectedItem.ToString();
			font_size = (int)comboFontSize.SelectedItem;
			font_style = (italic ? FontStyle.Italic : FontStyle.Regular) | (bold ? FontStyle.Bold : FontStyle.Regular);
			matrix_data = new bool[words_length, grid_width, grid_height];
			font = new Font(font_name, font_size, font_style, GraphicsUnit.Pixel);

			bitmaps = new Bitmap[words_length];
			pictureboxes = new PictureBox[words_length];

			for (int count = 0; count < words_length; count++) {
				bitmaps[count] = new Bitmap(grid_width, grid_height);

				using(Graphics g = Graphics.FromImage(bitmaps[count])) {
					g.Clear(Color.White);
					g.DrawString(words[count].ToString(), font, Brushes.Black, new PointF(adjust_x, adjust_y));
				}

				for (int y = 0; y < grid_height; y++) {
					for (int x = 0; x < grid_width; x++) {
						matrix_data[count, x, y] = bitmaps[count].GetPixel(x, y).GetBrightness() > 0.5 ? false : true;
					}
				}

				pictureboxes[count] = new PictureBox {
					Margin = new Padding(0),
					Size = new Size(grid_width * grid_size, grid_height * grid_size)
				};
				flowLayoutMatrix.Controls.Add(pictureboxes[count]);

				bitmaps[count] = new Bitmap(grid_width * grid_size, grid_height * grid_size);
				
				using(Graphics g = Graphics.FromImage(bitmaps[count])) {
					Brush brush;
					Pen pen = new Pen(Color.Black, 2);
					Rectangle rectangle;

					for (int x = 0; x < grid_width; x++) {
						for (int y = 0; y < grid_height; y++) {
							brush = matrix_data[count, x, y] ? Brushes.Black : Brushes.Green;
							rectangle = new Rectangle() { X = x * grid_size, Y = y * grid_size, Width = grid_size, Height = grid_size };

							g.FillRectangle(brush, rectangle);
							g.DrawRectangle(pen, rectangle);
						}
					}

					g.DrawRectangle(new Pen(Color.OrangeRed, 4), new Rectangle() {X = 0, Y = 0, Width = grid_width * grid_size, Height = grid_height * grid_size });
				}

				pictureboxes[count].Image = bitmaps[count];

				generate_output_code();
			}
		}

		private void generate_output_code()
		{
			StringBuilder output = new StringBuilder();
			string binary = string.Empty;
			string[] words = str2hex(txtWords.Text);

			for (int count = 0; count < matrix_data.GetLength(0); count++) {
				output.AppendFormat("# [{0}], size: ({1} * {2})", txtWords.Text[count], grid_width, grid_height).AppendLine();
				output.AppendFormat("{0}: [", words[count]);

				for (int y = 0; y < grid_height; y++) {
					for (int x = 0; x < grid_width; x++) {
						binary += matrix_data[count, x, y] ? "1" : "0";

						if (binary.Length == 8) {
							output.AppendFormat("0x{0:X2}", Convert.ToInt32(binary, 2)).Append(", ");

							binary = string.Empty;
						}
					}

					if (binary.Length > 0) {
						output.AppendFormat("0x{0:X2}", Convert.ToInt32(binary, 2)).Append(", ");

						binary = string.Empty;
					}
				}

				output = output.Remove(output.Length - 2, 2);
				output.AppendLine("],").AppendLine();
			}

			txtOutput.Text = output.Remove(output.Length - 5, 5).AppendLine().ToString();
		}

		private string[] str2hex(string str)
		{
			string[] result = new string[str.Length];
			byte[] temp;

			for (int count = 0; count < str.Length; count++) {
				temp = Encoding.GetEncoding("utf-8").GetBytes(str[count].ToString());

				if (temp.Length < 3) {
					result[count] = string.Format("0x{0:x2}", temp[0]);
				} else {
					result[count] = string.Format("0x{0:x2}{1:x2}{2:x2}", temp[0], temp[1], temp[2]);
				}
			}

			return result;
		}

		private void comboBoxFonts_SelectionChangeCommitted(object sender, EventArgs e)
		{
			generate_matrix();
		}

		private void txtWords_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter) {
				generate_matrix();
			}
		}

		private void comboBoxGridWidth_SelectionChangeCommitted(object sender, EventArgs e)
		{
			if (checkBoxGradSizeLocked.Checked) {
				comboBoxGridHeight.SelectedIndex = comboBoxGridWidth.SelectedIndex;
			}

			generate_matrix();
		}

		private void comboBoxGridHeight_SelectionChangeCommitted(object sender, EventArgs e)
		{
			if (checkBoxGradSizeLocked.Checked) {
				comboBoxGridWidth.SelectedIndex = comboBoxGridHeight.SelectedIndex;
			}

			generate_matrix();
		}

		//private void button1_Click(object sender, EventArgs e)
		//{
		//	Thread thread = new Thread(new ThreadStart(generate_dict));
		//	thread.Start();
		//}

		//private void generate_dict()
		//{
		//	using (FileStream fs = new FileStream("dict.txt", FileMode.Create, FileAccess.Write)) {
		//		using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
		//			for (long x = 0; x < 1000000; x++) {
		//				sw.WriteLine(x.ToString("X12"));
		//			}
		//		}
		//	}
		//}

		private void buttonUp_Click(object sender, EventArgs e)
		{
			adjust_position(y:-1);
		}

		private void buttonDown_Click(object sender, EventArgs e)
		{
			adjust_position(y:1);
		}

		private void buttonLeft_Click(object sender, EventArgs e)
		{
			adjust_position(x:-1);
		}

		private void buttonRight_Click(object sender, EventArgs e)
		{
			adjust_position(x:1);
		}

		private void txtAdjust_KeyUp(object sender, KeyEventArgs e)
		{
			switch (e.KeyCode) {
				case Keys.Up:
					adjust_position(y: -1);

					break;
				case Keys.Down:
					adjust_position(y: 1);

					break;
				case Keys.Left:
					adjust_position(x: -1);

					break;
				case Keys.Right:
					adjust_position(x: 1);

					break;
			}
		}

		private void checkItalic_CheckedChanged(object sender, EventArgs e)
		{
			italic = checkItalic.Checked;

			generate_matrix();
		}

		private void buttonZoomIn_Click(object sender, EventArgs e)
		{
			comboBoxGridWidth.SelectedIndex += (comboBoxGridWidth.SelectedIndex + 1 == comboBoxGridWidth.Items.Count) ? 0 : 1;
			comboBoxGridHeight.SelectedIndex += (comboBoxGridHeight.SelectedIndex + 1 == comboBoxGridHeight.Items.Count) ? 0 : 1;

			generate_matrix();
		}

		private void buttonZoomOut_Click(object sender, EventArgs e)
		{
			comboBoxGridWidth.SelectedIndex -= (comboBoxGridWidth.SelectedIndex - 1 == -1) ? 0 : 1;
			comboBoxGridHeight.SelectedIndex -= (comboBoxGridHeight.SelectedIndex - 1 == -1) ? 0 : 1;

			generate_matrix();
		}

		private void frmMain_KeyPress(object sender, KeyPressEventArgs e)
		{
			if (e.KeyChar == (char) Keys.Escape) {
				txtWords.Focus();
				txtWords.SelectAll();
			}
		}

		private void frmMain_KeyDown(object sender, KeyEventArgs e)
		{
			// Console.WriteLine(e.KeyCode);

			if (e.Control) {
				switch (e.KeyCode) {
					case Keys.Left:
						adjust_position(x:-1);
						e.Handled = true;

						break;
					case Keys.Right:
						adjust_position(x:1);
						e.Handled = true;
						
						break;
					case Keys.Up:
						adjust_position(y: -1);
						e.Handled = true;
						
						break;
					case Keys.Down:
						adjust_position(y: 1);
						e.Handled = true;
						
						break;
					case Keys.F:
						comboFonts.Select();
						e.Handled = true;

						break;
					case Keys.S:
						comboFontSize.Select();
						e.Handled = true;

						break;
					case Keys.B:
						checkBold.Checked = !checkBold.Checked;
						e.Handled = true;

						break;
					case Keys.I:
						checkItalic.Checked = !checkItalic.Checked;
						e.Handled = true;

						break;
					case Keys.Oemplus:
					case Keys.Add:
						buttonZoomIn_Click(null, null);
						e.Handled = true;

						break;
					case Keys.OemMinus:
					case Keys.Subtract:
						buttonZoomOut_Click(null, null);
						e.Handled = true;

						break;
					case Keys.PageUp:
						trackBarGridSize.Value += trackBarGridSize.Value >= trackBarGridSize.Maximum ? 0 : 1;
						e.Handled = true;

						break;
					case Keys.PageDown:
						trackBarGridSize.Value -= trackBarGridSize.Value <= trackBarGridSize.Minimum ? 0 : 1;
						e.Handled = true;

						break;
				}
			}

		}

		private void txtOutput_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Right) {
				if (txtOutput.SelectionLength == 0) {
					txtOutput.SelectAll();
				}
			}
		}

		private void trackBarGridSize_ValueChanged(object sender, EventArgs e)
		{
			labelGridSize.Text = trackBarGridSize.Value.ToString();

			generate_matrix();
		}

		private void checkBold_CheckedChanged(object sender, EventArgs e)
		{
			bold = checkBold.Checked;

			generate_matrix();
		}

		private void comboFontSize_SelectionChangeCommitted(object sender, EventArgs e)
		{
			generate_matrix();
		}

		private void adjust_position(int x=0, int y=0)
		{
			adjust_x += x;
			adjust_y += y;

			txtAdjust.Text = string.Format("({0:d}, {1:d})", adjust_x, adjust_y);

			generate_matrix();
		}
	}
}
